package cn.icanci.ladybird.common.util.task;

import cn.icanci.ladybird.common.util.cache.RedisUtils;
import cn.icanci.ladybird.pojo.entity.OrderInfo;
import cn.icanci.ladybird.pojo.entity.TicketSeat;
import cn.icanci.ladybird.service.OrderInfoService;
import cn.icanci.ladybird.service.TicketSeatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author: icanci
 * @date: Created in 2020/10/14 9:02
 * @classAction: 延时任务管理类
 */
@SuppressWarnings("all")
@Component
@Slf4j
public class DelayQueueManager implements CommandLineRunner {

    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private TicketSeatService ticketSeatService;

    /**
     * 延时队列
     */
    private DelayQueue<DelayTask> delayQueue = new DelayQueue<>();

    /**
     * 加入到延时队列中
     *
     * @param task 延时任务
     */
    public void put(DelayTask task) {
        log.info("加入延时任务：{}", task);
        delayQueue.put(task);
    }

    /**
     * 取消延时任务
     *
     * @param task 延时任务
     * @return 返回取消的结果
     */
    public boolean remove(DelayTask task) {
        log.info("取消延时任务：{}", task);
        return delayQueue.remove(task);
    }

    /**
     * 取消延时任务
     *
     * @param taskId 延时任务id
     * @return 返回 remove 结果
     */
    public boolean remove(String taskId) {
        return remove(new DelayTask(new TaskBase(taskId), 0));
    }

    @Override
    public void run(String... args) throws Exception {
        log.info("初始化延时队列");
        // 创建线程池
        // 获得 CPU 的核心数
        int num = Runtime.getRuntime().availableProcessors();
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                num,
                4,
                5,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());
        // 使用线程池
        pool.execute(new Thread(this::executeThread));
    }

    /**
     * 延时任务执行线程
     */
    private void executeThread() {
        while (true) {
            try {
                DelayTask task = delayQueue.take();
                processTask(task);
            } catch (InterruptedException e) {
                break;
            }
        }
    }

    /**
     * 内部执行延时任务
     *
     * @param task 延时任务
     */
    private void processTask(DelayTask task) {
        log.info("执行延时任务：{}", task);
        // 拿到data中的id，强转为Long类型，然后查询数据库订单的状态，
        Long value = Long.valueOf(task.getData().getIdentifier());
        OrderInfo orderInfo = orderInfoService.queryById(value);
        // 订单不为空，并且未付款
        // 如果订单未付款，设置订单状态为已经关闭，
        if (null != orderInfo && orderInfo.getOrderInfoStatus().equals(0)) {
            orderInfo.setOrderInfoStatus(2);
            orderInfoService.update(orderInfo);
            // 把订单相关的座位释放掉
            // 从redis找到数据订单id
            // 根据订单id获取座位的集合，设置状态为未售可选
            // 这个地方可以从数据库中取出，但是这里选择从Redis中去
            List<Long> seats = (List<Long>) redisUtils.get(String.valueOf(orderInfo.getOrderInfoId()));
            for (Long seat : seats) {
                TicketSeat ticketSeat = ticketSeatService.queryById(seat);
                ticketSeat.setTicketState(2);
                ticketSeat.setUpdateTime(new Date());
                ticketSeatService.update(ticketSeat);
            }
        } else {
            // 如果订单已经付款，则移除队列
            remove(task);
        }
    }
}
